package mySwingToolkit.model;

import java.util.LinkedHashSet;
import java.util.List;
import java.util.ListIterator;
import java.util.Set;
import javax.swing.table.DefaultTableModel;

/**
 * 添加了编辑开关的DefaultTableModel
 * @author hxd
 *
 */
public abstract  class SwitchedTableModel<T> extends DefaultTableModel{
	
	private Class<?>[] columnTypes;
	private boolean[] columnEditables;
	//数据模型
	/**
	 * 数据
	 */
	private List<ClassModel<T>> datas;
	/**
	 * 数据指针
	 */
	private ListIterator<ClassModel<T>> iter;
	
	private Set<ClassModel<T>> deleteDatas=new LinkedHashSet<ClassModel<T>>();
	private Set<ClassModel<T>> updateDatas=new LinkedHashSet<ClassModel<T>>();
	private Set<ClassModel<T>> insertDatas=new LinkedHashSet<ClassModel<T>>();
	
	/**
	 * 一页默认大小
	 */
	private int defaultSize=5;

	/**
	 * 当前页数据数量
	 */
	private int currentPageSize;
	/**
	 * 当前页
	 */
	private int currentPage=0;
	/**
	 * 总页数
	 */
	private int totalPage=0;
	/**
	 * 表格的列数，默认有一个隐藏列,一个序号列
	 */
	private int columnCount=2;
	/**
	 * 与view的编辑开关相对应,决定是否可以编辑
	 */
	private boolean editSwitch=false;
	/**
	 * 是否暂时屏蔽controller的tableChanged事件
	 */
	private boolean catchChangedEvent=true;
	private Object[] columnNames;
	public SwitchedTableModel() {
		super(new Object[][]{},new String[2]);
	}
	/**
	 * 第一列应该是一个对象，可以为null
	 * <br>如一行数据是由以下类构成
	 * <br>class Person{
	 * <br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String name;
	 * <br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String age;
	 * <br>}<br>
	 * 且表格一行有两列，分别是name,age。
	 * 则column应有4列，第一列为ClassModel<\Person>,第二列为序号、第三、四列为name或age
	 * @param columnNames
	 * @param rowCount 
	 * @param columnTypes 每列的类型，若为null而未重写getColumnClass方法，则为Object.class
	 * @param columnEditables 每列可否编辑，若为null且未重写isCellEditable方法或未其他设置，则可编辑
	 */
	public SwitchedTableModel(Object[] columnNames, int rowCount,Class<?>[] columnTypes,boolean[] columnEditables) {
		this.columnNames=new Object[columnNames.length+2];
		this.columnNames[0]="ClassModel";
		this.columnNames[1]="序号";
		for(int i=0;i<columnNames.length;i++){
			this.columnNames[i+2]=columnNames[i];
		}
		super.setColumnIdentifiers(this.columnNames);
		//super(columnNames, rowCount);
		columnCount=columnNames.length+2;
		this.setRowCount(rowCount);
		this.columnTypes=new Class<?>[columnTypes.length+2];
		this.columnTypes[0]=ClassModel.class;
		this.columnTypes[1]=Long.class;
		for(int i=0;i<columnTypes.length;i++){
			this.columnTypes[i+2]=columnTypes[i];
		}
		this.columnEditables=new boolean[columnEditables.length+2];
		this.columnEditables[0]=false;
		this.columnEditables[1]=false;
		for(int i=0;i<columnEditables.length;i++){
			this.columnEditables[i+2]=columnEditables[i];
		}
		
		//this.columnEditables=columnEditables;
		// TODO Auto-generated constructor stub
	}

	/**
	 * @see public SwitchedTableModel(Object[] columnNames, int rowCount)
	 * @param data 表格数据
	 * @param columnNames 每列的名字
	 * @param columnTypes 每列的类型，若为null而未重写getColumnClass方法，则为Object.class
	 * @param columnEditables 每列可否编辑，若为null且未重写isCellEditable方法或未其他设置，则可编辑
	 */
	public SwitchedTableModel(Object[][] data, Object[] columnNames,Class<?>[] columnTypes,boolean[] columnEditables) {
		this(columnNames,0,columnTypes,columnEditables);
	}
	
	
	
	public Class<?>[] getColumnTypes() {
		return columnTypes;
	}
	public void setColumnTypes(Class<T>[] columnTypes) {
		this.columnTypes = columnTypes;
	}
	public boolean[] getColumnEditables() {
		return columnEditables;
	}
	public void setColumnEditables(boolean[] columnEditables) {
		this.columnEditables = columnEditables;
	}
	
	public List<ClassModel<T>> getDatas() {
		return datas;
	}
	public void setDatas(List<ClassModel<T>> datas) {
		this.datas = datas;
	}
	public ListIterator<ClassModel<T>> getIter() {
		return iter;
	}
	public void setIter(ListIterator<ClassModel<T>> iter) {
		this.iter = iter;
	}
	public Object[] getColumnNames() {
		return columnNames;
	}
	public void setColumnNames(Object[] columnNames) {
		this.columnNames = columnNames;
	}
	
	/**
	 * 重设数据
	 * @param datas
	 */
	public void resetDatas(List<ClassModel<T>> datas){
		this.datas=datas;
		if(datas!=null){
			this.currentPage=0;
			this.totalPage=(this.datas.size()+this.defaultSize-1)/this.defaultSize;
			this.iter=this.datas.listIterator();	
		}
	
	}
	
	
	
	public Set<ClassModel<T>> getDeleteDatas() {
		return deleteDatas;
	}
	public void setDeleteDatas(Set<ClassModel<T>> deleteDatas) {
		this.deleteDatas = deleteDatas;
	}
	public Set<ClassModel<T>> getUpdateDatas() {
		return updateDatas;
	}
	public void setUpdateDatas(Set<ClassModel<T>> updateDatas) {
		this.updateDatas = updateDatas;
	}
	public Set<ClassModel<T>> getInsertDatas() {
		return insertDatas;
	}
	public void setInsertDatas(Set<ClassModel<T>> insertDatas) {
		this.insertDatas = insertDatas;
	}
	public int getDefaultSize() {
		return defaultSize;
	}
	public void setDefaultSize(int defaultSize) {
		this.defaultSize = defaultSize;
	}
	public int getCurrentPageSize() {
		return currentPageSize;
	}
	public void setCurrentPageSize(int currentPageSize) {
		this.currentPageSize = currentPageSize;
	}
	public int getCurrentPage() {
		return currentPage;
	}
	public void setCurrentPage(int currentPage) {
		this.currentPage = currentPage;
	}
	public int getTotalPage() {
		return totalPage;
	}
	public void setTotalPage(int totalPage) {
		this.totalPage = totalPage;
	}
	public int getColumnCount() {
		return columnCount;
	}
	public void setColumnCount(int columnCount) {
		this.columnCount = columnCount;
	}

	public boolean isEditSwitch() {
		return editSwitch;
	}
	public void setEditSwitch(boolean editSwitch) {
		this.editSwitch = editSwitch;
	}
	
	public boolean isCatchChangedEvent() {
		return catchChangedEvent;
	}
	public void setCatchChangedEvent(boolean catchChangedEvent) {
		this.catchChangedEvent = catchChangedEvent;
	}
	public void markDelete(int row){
		@SuppressWarnings("unchecked")
		ClassModel<T> obj=(ClassModel<T>) this.getValueAt(row, 0);
		this.updateDatas.remove(obj);
		this.insertDatas.remove(obj);
		obj.markDelete();
		this.deleteDatas.add(obj);
	}
	public void markUpdate(int row){
		@SuppressWarnings("unchecked")
		ClassModel<T> obj=(ClassModel<T>) this.getValueAt(row, 0);
		if(!this.insertDatas.contains(obj)){
			obj.markUpdate();
			this.updateDatas.add(obj);
		}
	}
	public void markInsert(int row){
		@SuppressWarnings("unchecked")
		ClassModel<T> obj=(ClassModel<T>) this.getValueAt(row, 0);
		obj.markInsert();
		this.insertDatas.add(obj);
		this.iter.add(obj);
	}
	
	public void nextPage(){
		this.catchChangedEvent=false;
		this.setRowCount(0);
		this.catchChangedEvent=true;
		if(this.datas!=null){
			this.currentPageSize=0;
			if(this.currentPage<this.totalPage){
				for(int i=0;i<this.defaultSize;i++){
					if(this.iter.hasNext()){
						Object[] obj=this.translate(this.iter.next());
						addRow(obj);
						this.currentPageSize++;
					}else{
						break;
					}
				}
				this.currentPage++;
			}
			this.setRowCount(this.getRowCount()+1);
			//this.addRow(new Object[this.columnCount]);	
		}
	}
	public void prePage(){
		if(this.datas!=null){
			if(this.currentPage>1){
				for(int i=0;i<this.currentPageSize+this.defaultSize;i++){
					if(this.iter.hasPrevious())
						this.iter.previous();
				}
				this.currentPage-=2;
				this.nextPage();
			}
		}
	}
	public void gotoPage(int page){
		if(this.datas!=null){
			if(page<1){
				page=0;
			}
			if(page>=this.totalPage){
				page=this.totalPage-1;
			}
			this.currentPage=page;
			this.iter=this.datas.listIterator(page*this.defaultSize);
			this.nextPage();
		}
	}
	
	@Override
	public String getColumnName(int column) {
		// TODO Auto-generated method stub
		return super.getColumnName(column);
	}
	@Override
	public Class<?> getColumnClass(int columnIndex) {
		if(columnTypes!=null)
			return columnTypes[columnIndex];
		else
			return super.getColumnClass(columnIndex);
	}
	@SuppressWarnings("unchecked")
	@Override
	public boolean isCellEditable(int row, int column) {
		if(columnEditables==null){
			return super.isCellEditable(row, column);
		}
		else if(editSwitch){
			ClassModel<T> c=(ClassModel<T>)this.getValueAt(row, 0); 
			if(c!=null&&c.getStatus()==ClassModel.DELETE)
				return false;	
			else
				return columnEditables[column];
		}else{
			return false;
		}
	}
	/**
	 * 返回的第一项应该是一个隐藏列
	 * @param object
	 * @return
	 */
	public  abstract Object[] translate(ClassModel<T> object);
	/**
	 * 将一行数据翻译成一个类
	 * @param row
	 * @return
	 */
	//public abstract T constructObject(int row,int col,T obj);
	
	public  abstract T constructObject(int row,int col);
}
